#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>

#define PORT 8888 // 定义服务器监听端口
#define BUFFER_SIZE 1024 // 定义数据缓冲区大小

int main(int argc,const char*argv[])
{
    //创建UDP套接字
    // AF_INET: IPv4地址族
    // SOCK_DGRAM: 数据报套接字(UDP)
    // 0: 默认协议
    int sockfd = socket(AF_INET,SOCK_DGRAM,0);
    if(sockfd == -1)
    {
        perror("socket创建失败");
        return -1;
    }

    //配置服务器地址结构体
    struct sockaddr_in serverInfo;

    memset(&serverInfo,0,sizeof(serverInfo));// 清空服务器地址结构体
    serverInfo.sin_family = AF_INET;
    serverInfo.sin_port = htons(PORT);
    //这里表示要监听所有网卡
    serverInfo.sin_addr.s_addr = INADDR_ANY;

    //绑定套接字到地址和端口
    int ret_bind = bind(sockfd,(struct sockaddr*)&serverInfo,sizeof(serverInfo));
    if(ret_bind == -1)
    {
        perror("绑定失败：");
        close(sockfd);
        return -1;
    }
    printf("UDP服务器已启动，监听端口：%d \n",PORT);

    //循环接收并回显数据
    while(1)
    {
        char buf[BUFFER_SIZE] = {0};// 数据接收缓冲区
        struct sockaddr_in clientInfo;// 客户端地址信息
        socklen_t clientInfo_len = sizeof(clientInfo); // 客户端地址结构体长度

        //接收数据
        ssize_t recv_len = recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr*)&clientInfo,&clientInfo_len);
        if(recv_len == -1)
        {
            perror("接收数据失败：");
            continue;//继续等待下一个数据包
        }

        //打印客户端信息
        printf("收到来自%s: %d的信息：%s\n",
            inet_ntoa(clientInfo.sin_addr),// 将IP地址转换为点分十进制字符串
            ntohs(clientInfo.sin_port),// 将端口号从网络字节序转换为主机字节序
            buf);// 接收到的数据内容
        
        //回显数据
        ssize_t send_len = sendto(sockfd,buf,recv_len,0,(struct sockaddr*)&clientInfo,clientInfo_len);
        if(send_len == -1)
        {
            perror("回显数据失败：");
        }
    }  
    close(sockfd);  

    return 0;
}
